home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Graphics⁄Sound / Contours source / fractal.c next >
C/C++ Source or Header  |  1986-04-19  |  16KB  |  579 lines

  1. /*
  2. **  Three-dimensional Fractal Contour Map generator.
  3. **  Program originally in MicroSoft BASIC for the Macintosh.
  4. **  Taken from July 1985 Creative Computing.
  5. **
  6. **  Used as an example BASIC-C comparison.
  7. */
  8.  
  9. #include <memory.h>
  10. #include <quickdraw.h>
  11. #include <font.h>
  12. #include <window.h>
  13. #include <osutil.h>
  14. #include <menu.h>
  15. #include <event.h>
  16. #include <textedit.h>
  17. #include <dialog.h>
  18. #include <desk.h>
  19. #include <control.h>
  20. #include <toolutil.h>
  21. #define watchCursor 4    /* Should be in TOOLUTIL.H but isn't.  JEC */
  22. #include <resource.h>
  23. #include <stdio.h>
  24.  
  25. #include "fractal.h"
  26.  
  27. GrafPtr screenport;        /* A port for the whole screen. */
  28. WindowPtr mywindow;        /* Our one window. */
  29. WindowRecord wrecord;        /* Storage for window record. */
  30. MenuHandle mymenus[LASTMENU + 1]; /* Our menus. */
  31. PicHandle thepicture;
  32. BitMap savepix;            /* Storage for the update bitmap. */
  33.  
  34. EventRecord myevent;
  35. WindowPtr whichwindow;        /* Points to window of MouseDown. */
  36. int windowcode;            /* What mouse was in when event posted. */
  37. Boolean userdone;        /* True when user wants to exit program. */
  38. int ispicture;        /* True if there is a Picture definition of the
  39.                contour available. */
  40. int isbitmap;        /* True if there is a bitmap copy of the contour
  41.                available.  Saves time in update events. */
  42. int usebitmap;        /* True if the bitmap should be used to update. */
  43.  
  44. main() {
  45.     setup();
  46.     maineventloop();
  47. }
  48.  
  49. /*############################   MainEventLoop  ########################*/  
  50.  
  51. maineventloop() {
  52.  
  53.     FlushEvents(everyEvent, 0);/* discard leftover events */
  54.  
  55. /* get next event, and handle it appropriately, until user QUITs */
  56.  
  57.     userdone = 0;
  58.     do {
  59.     SystemTask();        /* Handle desk accessories. */
  60.     if (GetNextEvent(everyEvent, &myevent)) {
  61.                 /* get event; if for us... */
  62.         switch (myevent.what) {/* handle each kind of event */
  63.         case mouseDown: /* find out what window the mouse went
  64.                    down in, and where in it */
  65.             windowcode = FindWindow(pass(myevent.where), &whichwindow);
  66.             switch (windowcode) {
  67.                 /* handle mouse-down for each place */
  68.             case inSysWindow: 
  69.                 /* handle the desk accessories */
  70.                 SystemClick(&myevent, whichwindow);
  71.                 break;/* insyswindow */
  72.             case inMenuBar: /* handle the command */
  73.                 userdone = docommand(MenuSelect(&myevent.where));
  74.                 break;/* inmenubar */
  75.             case inDrag: /* No Drag Region, treat as Content. */
  76.             case inContent: 
  77.                 /* includes inGrow if window inactive.
  78.                    Activate window */
  79.                 if (whichwindow == mywindow)
  80.                 /* make sure it's for mine */
  81.                 if (whichwindow != FrontWindow())
  82.                     SelectWindow(whichwindow);
  83.                 /* make it active */
  84.                 break;
  85.             case inGrow: /* No Grow Region */
  86.                 break;
  87.             case inGoAway: 
  88.                 /* we don't have a GoAway region */
  89.                 break;
  90.             }
  91.             break;    /* switch */
  92.  
  93.         case keyDown: 
  94.         case autoKey:     /* if command key, pass the char to
  95.                    MenuKey */
  96.             if ((myevent.modifiers & cmdKey) != 0)
  97.             userdone = docommand(MenuKey((char) (myevent.message & charCodeMask)));
  98.         case updateEvt: /* if it's for our window, update it */
  99.             if ((WindowPtr) (myevent.message) == mywindow)
  100.             updatewindow(mywindow);
  101.                 /* redraw the window contents */
  102.             break;
  103.         case activateEvt: 
  104.                 /* if for our window, set port as nec. */
  105.             if ((WindowPtr) (myevent.message) == mywindow) {
  106.                 /* my window */
  107.             if (myevent.modifiers & 1) {
  108.                 /* odd means an activate event */
  109.                 SetPort(mywindow);
  110.                 /* activate evt: work in our own port */
  111.                 DisableItem(mymenus[EDITMENU], 0);
  112.                 EnableItem(mymenus[FILEMENU], 0);
  113.                 EnableItem(mymenus[SETUPMENU], 0);
  114.                 DrawMenuBar();
  115.             }
  116.             else {
  117.                 SetPort(screenport);
  118.                 /* deactivate evt: our port is gone; keep
  119.                    port from dangling */
  120.                 EnableItem(mymenus[EDITMENU], 0);
  121.                 DisableItem(mymenus[FILEMENU], 0);
  122.                 DisableItem(mymenus[SETUPMENU], 0);
  123.                 DrawMenuBar();
  124.             }
  125.             } break;
  126.         }
  127.     }
  128.  
  129.     } while (userdone == 0);
  130. }
  131.  
  132. /*
  133. handle a command given through a menu selection
  134. ############################   DoCommand   ##############################
  135.  
  136.    We carry out the command indicated by mResult.
  137.    If it was Quit, we return true, else false.  Since the menu was
  138.    highlighted by MenuSelect, we must finish by unhighlighting it
  139.    to indicate we're done.
  140. */
  141. int     docommand(mresult)
  142. long    mresult;
  143. {
  144.     int     refnum;
  145.     int     themenu,
  146.             theitem;
  147.     char    name[255];
  148.     GrafPtr saveport;        /* for saving current port in when opening
  149.                    a desk accessory */
  150.     int     returns;
  151.  
  152.     returns = 0;        /* assume Quit not selected */
  153.     themenu = HiWord(mresult);    /* get the menu selected */
  154.     theitem = LoWord(mresult);    /* ... and the item of that menu */
  155.     switch (themenu) {
  156.     case 0: 
  157.         break;        /* user made no selection; do nothing */
  158.  
  159.     case APPLEMENU: 
  160.  
  161.         if (theitem == 1)    /* Tell about FracCont */
  162.         report();
  163.         else {        /* run a desk accessory; make sure port is
  164.                    preserved */
  165.         GetPort(&saveport);
  166.         GetItem(mymenus[APPLEMENU], theitem, name);
  167.                 /* get name */
  168.         refnum = OpenDeskAcc(name);/* run the desk accessory */
  169.         SetPort(saveport);
  170.         }
  171.         break;
  172.  
  173.     case FILEMENU: 
  174.         switch (theitem) {
  175.         case ANOTHER:     /* New Surface */
  176.             calcsurf(contlevl);
  177.             InvalRect(&mywindow -> portRect);
  178.             usebitmap = FALSE;
  179.             break;
  180.         case SAVEPAINT: /* Not yet. */
  181.             break;
  182.         case IQUIT: 
  183.             returns = 1;/* Quit */
  184.             break;
  185.         }            /* FILEMENU case */
  186.         break;
  187.  
  188.     case SETUPMENU: 
  189.         switch (theitem) {
  190.         case SETUP:     /* Setup */
  191.             setupDlg();
  192.             break;
  193.         }            /* SETUPMENU case */
  194.  
  195.     }                /* menu case */
  196.  
  197.     HiliteMenu(0);        /* turn off hilighting on the menu just
  198.                    used */
  199.     return (returns);
  200. }                /* DoCommand */
  201.  
  202. /*############################   Setup Dialog   ######################*/
  203.  
  204. TerrainBTN(ptr, oncontrl, offcontrl)
  205. DialogPtr ptr;
  206. int oncontrl, offcontrl;
  207. {
  208.     int itemtype;
  209.     ControlHandle item;
  210.     Rect itembox;
  211.  
  212.     GetDItem(ptr, offcontrl, &itemtype, &item, &itembox);
  213.     SetCtlVal(item, 0);    /* Turn off old Default Button. */
  214.     GetDItem(ptr, oncontrl, &itemtype, &item, &itembox);
  215.     SetCtlVal(item, 1);    /* Turn on Default Button. */
  216.     return oncontrl;
  217. }
  218.     
  219. setupDlg()            /* Do the SETUP menu dialog. */
  220. {
  221.     int newtype;        /* Selected Contour type. */
  222.     int newlevel;        /* Selected Level of Detail. */
  223.     int userexit;
  224.     int doanother;        /* True if we need to recalc. */
  225.     int    itemhit;    /* Item # of punched button (or whatever) */
  226.     DialogPtr setupptr;
  227.     char asciibufr[10];
  228.     int itemtype;
  229.     ControlHandle item;
  230.     Rect itembox;
  231.     
  232.     newtype = conttype;    /* SETUPMTN, SETUPHIL, or SETUPWATR */
  233.     newlevel = contlevl;
  234.     doanother = FALSE;
  235.     
  236.     setupptr = GetNewDialog(STPDLGID, NULL, (long) -1);
  237.     TerrainBTN(setupptr, conttype, conttype);
  238.     asciibufr[1] = newlevel + '0';    /* Only good for 0..9, OK here. */
  239.     asciibufr[0] = 1;
  240.     GetDItem(setupptr, SETUPLEVL, &itemtype, &item, &itembox);
  241.     SetIText(item, asciibufr);
  242.     SelIText(setupptr, SETUPLEVL, 0, 100);    /* Hilite text field. */
  243.     userexit = FALSE;
  244.     do {
  245.         ModalDialog(NULL, &itemhit);
  246.                 /* carry out dialog; NIL => no FilterProc;
  247.                    return item Hit when done */
  248.         GetDItem(setupptr, SETUPLEVL, &itemtype, &item, &itembox);
  249.         GetIText(item, asciibufr);    /* Get Level field */
  250.         if (asciibufr[0] != 1)    /* Only good for 1..9, OK here. */
  251.             newlevel = 100;
  252.         else
  253.             newlevel = asciibufr[1] - '0';
  254.         if (newlevel < 1 || newlevel > MAXLEVEL)
  255.             SelIText(setupptr, SETUPLEVL, 0, 100);    /* Hilite text field. */
  256.         if (itemhit == SETUPMTN)
  257.             newtype = TerrainBTN(setupptr, itemhit, newtype);
  258.         if (itemhit == SETUPHIL)
  259.             newtype = TerrainBTN(setupptr, itemhit, newtype);
  260.         if (itemhit == SETUPWATR)
  261.             newtype = TerrainBTN(setupptr, itemhit, newtype);
  262.         if (itemhit == SETUPOK && ((newlevel > 0) & (newlevel <= MAXLEVEL))) {
  263.             if (conttype != newtype || contlevl != newlevel) {
  264.                 if (contlevl != newlevel)
  265.                     doanother = TRUE;
  266.                 InvalRect(&mywindow -> portRect);
  267.                 usebitmap = FALSE;
  268.             }
  269.             contlevl = newlevel;
  270.             conttype = newtype;
  271.             userexit = TRUE;
  272.         }
  273.         if (itemhit == SETUPCAN)
  274.             userexit = TRUE;
  275.     } while (!userexit);
  276.     DisposDialog(setupptr);    /* release storage and remove dialog from
  277.                        screen */
  278.     if (doanother)
  279.         calcsurf(newlevel);    /* Removes dialog first. */
  280. }    /* Setup */
  281.  
  282.  
  283. /* 
  284. ############################   Report   #################################
  285. */
  286.  
  287. report()
  288. {
  289.     int     itemhit;        
  290.     DialogPtr reportptr;
  291.  
  292.     reportptr = GetNewDialog(INFOSCR1, NULL, (long) -1);
  293.                 /* Get from Resource file; NIL => use heap
  294.                    storage; -1 => make dlg frontmost */
  295.  
  296.     ModalDialog(NULL, &itemhit);
  297.                 /* carry out dialog; NIL => no FilterProc;
  298.                    return item Hit when done */
  299.     DisposDialog(reportptr);    /* release storage and remove dialog from
  300.                    screen */
  301.     if (itemhit == INFOMORE) {
  302.     reportptr = GetNewDialog(INFOSCR2, NULL, (long) -1);
  303.     ModalDialog(NULL, &itemhit);
  304.     DisposDialog(reportptr);
  305.     }
  306. }
  307.  
  308.  
  309. /*
  310.  
  311. SetUps for handling memory
  312. ##########################   SetUpMemory   ############################
  313. */
  314.  
  315. setupmemory() {
  316.  
  317.  
  318. #define maxStackSize 8192    /* max size of stack; the heap gets the
  319.                    rest */
  320.  
  321.     typedef long   *lomemptr;    /* a pointer to low memory locations */
  322.  
  323.     lomemptr nilptr;        /* will have value NIL */
  324.     lomemptr stackbaseptr;    /* points to current stack base */
  325.  
  326. /* 
  327.   If you define a GrowZone function to handle bad memory problems,
  328.   you should define it at the top level (not nested), and set it
  329.   here. We don't.
  330. */
  331. /*  SetGrowZone(&mygrowzone);     */
  332.  
  333. /* 
  334.   Place a longint -1 (an odd and therefore illegal address) in the
  335.   memory location that would be referenced by an accidentally-NULL
  336.   handle, so the error will be caught at handle-reference time (as
  337.   an Address error, ID=02) instead of later on.
  338. */
  339.  
  340.     nilptr = NULL;
  341.     *nilptr = -1;
  342.  
  343. /* 
  344.   If you needed to use an Application heap limit other than the
  345.   default (which allows 8K for the stack), you'd set it here,
  346.   possible using this technique of explicitly specifying the maximum
  347.   stack size and allocating the rest to the heap.  Should be
  348.   independent of memory size. */
  349.  
  350.     stackbaseptr = (lomemptr) 0x908;
  351.                 /* CurStackBase from Tlasm/sysequ.text */
  352.     SetApplLimit((Ptr) (*stackbaseptr - maxStackSize));
  353.  
  354. /* 
  355.   Expand the application heap zone to its maximum size, without
  356.   purging any purgeable resources.  This saves memory compactions
  357.   and heap expansions later.
  358. */
  359.  
  360.     MaxApplZone();
  361.  
  362. /* 
  363.   get plenty of master pointers now; if we let the Memory Manager
  364.   allocate them as needed, they'd form non-relocatable islands in
  365.   the heap.
  366. */
  367.  
  368.     MoreMasters();
  369.     MoreMasters();
  370.  
  371. }                /* SetUpMemory */
  372.  
  373. /*
  374. ############################   SetUpMenus   #############################
  375.     Once-only initialization for menus
  376.     We read in all menus from the resource file, and install them,
  377.     and all desk accessories (drivers).
  378. */
  379.  
  380. setupmenus() {
  381.     int     i;
  382.     for (i = 1; i <= LASTMENU; i++)/* get all my menus in */
  383.     mymenus[i] = GetMenu(i);/* use the fact that our menu ID's start
  384.                    at 1 */
  385.     AddResMenu(mymenus[APPLEMENU], 'DRVR');
  386.                 /* pull in all desk accessories */
  387.     for (i = 1; i <= LASTMENU; i++)
  388.     InsertMenu(mymenus[i], 0);/* insert menus; 0 => put at end */
  389.     DrawMenuBar();
  390. }
  391.  
  392. /*
  393.     
  394. body of SetUp
  395. Once-only initialization.
  396. ############################   SetUp   ##############################
  397.  
  398.    Initialize our program.  It seems best to handle:
  399.    Memory inits first, ToolBox inits second, then the program variables'
  400.    inits. Note that the order of inits is important; see "Using the
  401.    Dialog Manager" in the Dialog Mgr section.
  402.  
  403. */
  404.  
  405. setup() {
  406.  
  407.     char *ctop();
  408.     
  409.     setupmemory();        /*  init memory layout and protection */
  410.  
  411. /*  init QuickDraw, and everybody else */
  412.  
  413.     InitGraf(&thePort);
  414.     InitFonts();
  415.     InitWindows();
  416.     InitMenus();
  417.     TEInit();
  418.     InitDialogs(NULL);        /* NULL => no Restart proc; see Dialog Mgr
  419.                    and System Error Handler */
  420.     InitCursor();
  421.  
  422. /* 
  423.   Init the system event mask, in case the previous program left
  424.   it in a bad state.  If you set it non-standard here, FIX IT
  425.   BEFORE EXITING, because the Finder (1.1g) does NOT set it.
  426. */
  427.     SetEventMask(everyEvent - keyUpMask);/* standard setting */
  428. /* 
  429.   Get the port which is the whole screen, to use when deactivating
  430.   our window.  This prevents the current grafPort pointer from
  431.   ever dangling.
  432. */
  433.     GetWMgrPort(&screenport);    /* get whole screen port that window mgr
  434.                    uses */
  435.     SetPort(screenport);    /* and start off with it */
  436.  
  437. /* 
  438.   get window: use wRecord storage.  Port is set to that of the
  439.   new window.
  440.   GetNewWindow posts an update event for the new window,
  441.   so it will be redrawn right away.
  442. */
  443. #ifdef DEVELOP
  444.     OpenResFile(ctop(DEVELOP));
  445. #endif
  446.     mywindow = GetNewWindow(WINDOWID, &wrecord, (long) -1);
  447.                 /* -1 => frontmost window */
  448.  
  449. /* pull in and set up our menus */
  450.     setupmenus();
  451.     CouldDialog(STPDLGID);    /* Preload the Setup Dialog. */
  452.  
  453.     conttype = DEFLTTYP;        /* Default style */
  454.     contlevl = DEFLTLEV;        /* Default Level */
  455.     isbitmap = FALSE;
  456.         /* Allocate the data array. */
  457.     points = NewPtr((long) XDIM*YDIM*(sizeof(int)));    /* Non-reloc, but so what. */
  458.     calcsurf(contlevl);        /* Do at least one first. */
  459. }
  460.  
  461. /*
  462.  
  463. Update the contents of the given window
  464. ############################   UpdateWindow   ##########################
  465.  
  466.    This is our response to receipt of an update event for myWindow.
  467.    Since the window is likely to be inactive, the current grafPort
  468.    will be elsewhere.  We must change it for drawing, yet leave it
  469.    as it was.
  470. */
  471.  
  472. updatewindow(awindow)
  473. WindowPtr awindow;
  474. {
  475.     GrafPtr saveport;        /* to save and restore the old port */
  476.  
  477.     BeginUpdate(awindow);    /* reset ClipRgn etc to only redraw what's
  478.                    necessary. */
  479.  
  480.     GetPort(&saveport);        /* don't trash the port; we might be
  481.                    updating an inactive window */
  482.     SetPort(awindow);        /* work in the specified window */
  483.  
  484.     drawwindow();        /* redraw contents of window */
  485.  
  486.     SetPort(saveport);        /* all nice and tidy as before */
  487.  
  488.     EndUpdate(awindow);
  489.  
  490. }                /* UpdateWindow */
  491.  
  492. /* 
  493. Redraw my window
  494. ############################   DrawWindow   #############################
  495.  
  496.    We draw all the contents of our one window, myWindow.
  497. */
  498.  
  499. drawwindow()
  500. {
  501.     /* Possibly save the drawing contents in a picture.  This will allow
  502.        much faster update events than calling plotdata() repeatedly.
  503.        This is only to speed up Desk Accessory movement and the
  504.        re-painting after the Options Dialog is removed. */
  505.     CursHandle ticktock;
  506.  
  507.     ticktock = GetCursor(watchCursor);
  508.     if (ticktock)
  509.         SetCursor(*ticktock);    /* Show watch (wait) */
  510.     if (usebitmap) {
  511.         CopyBits(&savepix, &mywindow->portBits,
  512.             &savepix.bounds, &mywindow->portRect,
  513.             srcCopy, 0L);
  514.     }
  515.     else {
  516.         if (isbitmap)
  517.             DisposPtr(savepix.baseAddr);
  518.         savepix.bounds.top = mywindow->portRect.top;
  519.         savepix.bounds.bottom = mywindow->portRect.bottom;
  520.         savepix.bounds.left = mywindow->portRect.left;
  521.         savepix.bounds.right = mywindow->portRect.right;
  522.         savepix.rowBytes = mywindow->portBits.rowBytes;
  523.         savepix.baseAddr = NewPtr((long) savepix.rowBytes *
  524.             (savepix.bounds.bottom - savepix.bounds.top));
  525.         EraseRect(&mywindow->portRect);
  526.         plotdata();
  527.         CopyBits(&mywindow->portBits, &savepix,
  528.             &mywindow->portRect, &savepix.bounds,
  529.             srcCopy, 0L);
  530.         isbitmap = usebitmap = TRUE;
  531.     }
  532. #ifdef not_defined
  533.     if (ispicture)
  534.         KillPicture(thepicture);
  535.     thepicture = OpenPicture(&mywindow -> portRect);
  536.     ShowPen();    /* We want the picture shown while being drawn. */
  537.     EraseRect(&mywindow -> portRect);
  538.     plotdata();
  539.     HidePen();    /* Balance the ShowPen() above. */
  540.     ClosePicture();
  541.     ispicture = TRUE;
  542. #endif
  543.     InitCursor();
  544. }                /* DrawWindow */
  545.  
  546. /*
  547.  *    The following routine was used while debugging and testing the program.
  548.  *    The routine is called just like "printf()", but the output is
  549.  *    directed to the printer port. Use -7 for the modem port.  The
  550.  *    port must already be opened.  Use MIXCROOT and do a 2> .b(a)out
  551.  *    to easily do this.
  552.  */
  553.  
  554. #ifdef DEBUG
  555. debug(fmt, arg)
  556. char *fmt;
  557. unsigned arg;
  558. {
  559.     int put();
  560.  
  561.     format(put, fmt, &arg);
  562. }
  563.  
  564. put(c)
  565. char c;
  566. {
  567.     long i;
  568.  
  569.     i = 1;
  570.     if (c=='\n')
  571.         put('\r');
  572.     FSWrite(DEBUG, &i, &c);
  573.     if (c=='\n')
  574.         for (i=2000; i; i--)
  575.             ;
  576. }
  577. #endif
  578.  
  579.